package org.hzero.autoconfigure.gateway.helper;

import org.hzero.core.redis.RedisHelper;
import org.hzero.gateway.helper.api.AuthenticationHelper;
import org.hzero.gateway.helper.api.HelperFilter;
import org.hzero.gateway.helper.api.reactive.ReactiveAuthenticationHelper;
import org.hzero.gateway.helper.config.GatewayHelperProperties;
import org.hzero.gateway.helper.filter.SignatureAccessFilter;
import org.hzero.gateway.helper.impl.DefaultAuthenticationHelper;
import org.hzero.gateway.helper.impl.HelperChain;
import org.hzero.gateway.helper.impl.reactive.DefaultReactiveAuthenticationHelper;
import org.hzero.gateway.helper.service.CustomPermissionCheckService;
import org.hzero.gateway.helper.service.SignatureService;
import org.hzero.gateway.helper.service.impl.DefaultCustomPermissionCheckService;
import org.hzero.gateway.helper.service.impl.DefaultSignatureService;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Optional;

@ComponentScan(value = {
    "org.hzero.gateway.helper"
})
// 开启缓存
@EnableCaching
@Configuration
@EnableAsync
@Order(SecurityProperties.BASIC_AUTH_ORDER)
public class GatewayHelperAutoConfiguration {

    // 这里的参数会自动封装,会扫描spring 容器中是HelperFilter类型的 bean,组合成 list 作为参数
    // 前提是必须在Spring 的自动装配类配置中
    @Bean
    public HelperChain helperChain(Optional<List<HelperFilter>> optionalHelperFilters){
        return new HelperChain(optionalHelperFilters);
    }

    @Bean
    // 当应用程序是web应用程序时匹配的条件。默认情况下，任何web应用程序 将匹配，但可以使用type（）属性缩小范围。
    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
    // 在缺失某些类型的Bean的时候，才将方法返回的Bean装配到IoC容器中
    @ConditionalOnMissingBean(AuthenticationHelper.class)
    public DefaultAuthenticationHelper authenticationHelper(HelperChain helperChain) {
        // 当是 web 应用程序并且缺失自定义AuthenticationHelper的 bean 时,注入DefaultAuthenticationHelper这个 bean
        return new DefaultAuthenticationHelper(helperChain);
    }

    @Bean
    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
    @ConditionalOnMissingBean(ReactiveAuthenticationHelper.class)
    public DefaultReactiveAuthenticationHelper reactiveAuthenticationHelper(HelperChain helperChain) {
        // 当是 Reactive 响应式的 web 程序类型并且缺失ReactiveAuthenticationHelper的 bean 时,则将DefaultReactiveAuthenticationHelper注入
        // 和上面的DefaultAuthenticationHelper注入不冲突,是并列的存在
        return new DefaultReactiveAuthenticationHelper(helperChain);
    }

    @Bean(name = "helperRestTemplate")
    // 在RestTemplate上加入了注解@LoadBalanced。它的作用是让RestTemplate实现负载均衡，也就是，通过这个RestTemplate对象调用用户微服务请求的时候，Ribbon会自动给用户微服务节点实现负载均衡，这样请求就会被分摊到微服务的各个节点上，从而降低单点的压力。
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    @Bean
    // 当没有默认值时,判断匹配的条件就是当前 bean 定义方法的bean 在 application context 中不存在
    @ConditionalOnMissingBean
    // 这是一个检测属性配置的注解，代码中的配置也就是当存在属性hzero.gateway.helper.signature.enabled配置后，才会启动这个类作为配置文件。
    @ConditionalOnProperty(prefix = GatewayHelperProperties.PREFIX, value = "signature.enabled", havingValue = "true")
    public SignatureService signatureService(GatewayHelperProperties properties, RedisHelper redisHelper) {
        // 签名服务实现
        return new DefaultSignatureService(properties, redisHelper);
    }

    @Bean(name = "signatureAccessFilter")
    @ConditionalOnProperty(prefix = GatewayHelperProperties.PREFIX, value = "signature.enabled", havingValue = "true")
    public SignatureAccessFilter signatureAccessFilter(GatewayHelperProperties properties, SignatureService signatureService) {
        // 验证码签名
        return new SignatureAccessFilter(properties, signatureService);
    }

    @Bean
    // 指定 bean 名称?
    @Qualifier("permissionCheckSaveExecutor")
    public AsyncTaskExecutor commonAsyncTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setThreadNamePrefix("ps-check-save-");
        executor.setMaxPoolSize(200);
        executor.setCorePoolSize(50);
        return executor;
    }

    @Bean
    @ConditionalOnMissingBean(CustomPermissionCheckService.class)
    public CustomPermissionCheckService customPermissionCheckService() {
        // 默认自定义层级权限检查
        return new DefaultCustomPermissionCheckService();
    }

}
